package org.tigr.htc.request;

/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.io.IOException;
import java.util.Date;
import java.util.Map;

import org.tigr.antware.shared.command.events.CommandLifetimeLI;
import org.tigr.antware.shared.command.events.CommandRuntimeStatusLI;
import org.tigr.antware.shared.command.events.CommandStatusLI;
import org.tigr.htc.cmd.CmdState;
import org.tigr.htc.cmd.Command;
import org.tigr.htc.cmd.ParamType;
import org.tigr.htc.cmd.TaskGroup;

/**
 * The <b>IRequest</b> class is the main interface for users to submits
 * commands to the cluster. 
 * The IRequest interface is how you create a new command and submit
 * that command to the HTCServer.  You create a new IRequest through
 * RequestFactory.newRequest().  For a command to be valid it must at least
 * have a command and group. The username is automatically set to the owner of
 * the JVM process. 
 *
 * Example:
 *    IRequest req = RequestFactory.newRequest();
 *    req.setCommand("/usr/local/test.sh");
 *    req.setGroup("ANTWARE");
 *    req.submitAndWait();
 */    
public interface IRequest {
	
    /**
     * <code>LINUX</code> constant for setOpSys()
     */
    static final String LINUX = "linux";

    /**
     * <code>OSF1</code> constant for setOpSys()
     */
    static final String OSF1 = "osf1";

    /**
     * <code>SOLARIS</code> constant for setOpSys()
     */
    static final String SOLARIS = "solaris";

    /**
     * <code>VERY LOW</code> constant for setPriority
     */
    static final int VERY_LOW = 0;

    /**
     * <code>LOW</code> constant for setPriority
     */
    static final int LOW = 1;

    /**
     * <code>LOW</code> constant for setPriority
     */
    static final int MEDIUM = 2;

    /**
     * <code>LOW</code> constant for setPriority
     */
    static final int HIGH = 3;

    /**
     * <code>LOW</code> constant for setPriority
     */
    static final int VERY_HIGH = 4;

    // 
    // IRequest Methods
    //

    /**
     * <code>getID</code> associated with request
     *
     * @return a <code>long</code> value
     */
    public long getID();

    /**
     * <code>getUserName</code> gets the username that the request will
     * be run under.  The username defaults to the user that owns the 
     * JVM process which is defined by the user system property.
     *
     * @return a <code>String</code> value
     */
    public String getUserName();


    /**
     * <code>getState</code> gets the current state of the request.
     * The valid state are defined in the enum CmdState.
     *
     * @return a <code>CmdState</code> value
     */
    public CmdState getState();

    /**
     * <code>getReturnValue</code>
     *
     * @return a <code>CmdState</code> value
     */
    public int getReturnValue();


    /**
     * <code>getCommand</code> get the full path of Command.
     *
     * @return a <code>String</code> value
     */
    public String getCommand();

    /**
     * <code>getCommandObj</code> get the full path of Command.
     *
     * @return a <code>String</code> value
     */
    public Command getCommandObj();

    /**
     *  <code>setCommand</code> set the FULL path to the Command/executable 
     * you want to run. This is required to have a valid request and cannot
     * be empty or null.
     *  
     *  Example: setCommand("/usr/local/bin/blastp");
     *
     * @param pCommand a <code>String</code> that contains full command to run
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setCommand(String pCommand) throws IllegalAccessException;


    /**
     * <code>getGroup</code> get the group for the request.
     *
     * @return a <code>String</code> value
     */
    public String getGroup();

    /**
     *  <code>setGroup</code> set the group that is running the Command. 
     *  The group must be set to have a valid request.
     *
     *  Group examples: TGI, CMR, EGC
     *
     * @param pGroup a <code>String</code> that contains the group name
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setGroup(String pGroup) throws IllegalAccessException;


    /**
     * <code>setName</code> defined name for the command. It can be
     * any non-empty string. Here for user to have an English name 
     * instead of just a Command id.
     *
     * Example: setName("My Blast Command");
     *
     * @param pName a <code>String</code> that contains the command name
     * @exception IllegalAccessException if set is attempted after submission 
     */
    public void setName(String pName) throws IllegalAccessException;

    /**
     * <code>getInitialDir</code> get the path of the initial
     * working directory for the request.
     *
     * @return a <code>String</code> value
     */
    public String getInitialDir();

    /**
     * <code>setInitialDir</code> set the current working path of
     * the command when it is executed. If this initial directory is set
     * everything else (such as output & error) can be relative from it 
     * EXCEPT for the command.
     *
     * @param pDir a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setInitialDir(String pDir) throws IllegalAccessException;

    /**
     * <code>getOutput</code> get the file that STDOUT is being
     * redirected to.
     *
     * @return a <code>String</code> value
     */
    public String getOutput();

    /**
     *  <code>setOutput</code> setter for a file to send the what the 
     * command would usually send to the screen and STDOUT. This is
     * needed since the command will be running remotely. This can
     * be an absolute path or relative to InitialDir. If not set 
     * all output ignored and lost.
     *
     * @param pOutput a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setOutput(String pOutput) throws IllegalAccessException;

    /**
     * <code>getError</code> get the file that STDERR is being
     * redirected to.
     *
     * @return a <code>String</code> value
     */
    public String getError();

    /**
     * <code>setError</code> setter for a file to send the what the 
     * command would usually send to the screen or STDERR. This is
     * needed since the command will be running remotely. This can
     * be an absolute path or relative to InitialDir. If not set 
     * all output ignored and lost.
     *
     * @param pOutput a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setError(String pError) throws IllegalAccessException;


    /**
     * <code>getInput</code> get the file that STDIN is being
     * read from.
     *
     * @return a <code>String</code> value
     */
    public String getInput();

    /**
     *  <code>setInput</code> setter for a file to read STDIN 
     *  from. This is needed since the command will be run remotely and
     *  and input can't be read from the keyboard. If not set, input is
     *  ignored.  This can be an absolute path or relative to InitialDir.
     *
     * @param pInput a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setInput(String pInput) throws IllegalAccessException;

    /**
     * <code>getEmail</code> get the email address associated with a request if
     * it needs to be different than the username.
     *
     * @return a <code>String</code> value
     */
    public String getEmail();

    /**
     * <code>setEmail</code> set the email address associated 
     * with the request if it is needed to be different than the  
     * username@example.com
     *
     * @param pEmail a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setEmail(String pEmail) throws IllegalAccessException;

    /**
     * <code>getNotifyScript</code> get script to notify when Command is
     * finished.  
     *
     * @return a <code>String</code> value
     */
    public String getNotifyScript();
    
    /**
     * <code>setNotifyScript</code> set script to call when Command is 
     * finished. The script is executed and should expect the request id,
     * email address, and return value passed to it. 
     * 
     * If you were to register a "/path/to/script" then it would be called
     * like:
     *  /path/to/script -requestID=id -returnValue=val -message="string" -email="user@example.com"
     *
     * @param pScript a <code>String</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setNotifyScript(String pScript) throws IllegalAccessException;


    /* command add param methods */

    /**
     * <code>addParam</code> adds a value to the end of the
     * command line when the command is invoked.  The command line arguments
     * are appended in the order that they are added.
     *
     * Example:
     *    setCommand("/foo/test.sh");
     *    add_param("-v");
     *    add_param("database user");
     *
     * final command -> /foo/test.sh -v database user
     *
     * @param pValue a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addParam(String pValue) throws IllegalAccessException;
    
    /**
     * <code>addParam</code> adds a key=value to the end of the
     * command line when the command is invoked.  The command line arguments
     * are appended in the order that they are added.
     *
     * Example:
     *    setCommand("/foo/test.sh");
     *    add_param("-v");
     *    add_param("database", "user");
     *
     * final command -> /foo/test.sh -v database=user
     *
     * @param pKey a <code>String</code> value
     * @param pValue a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addParam(String pKey, String pValue) throws IllegalAccessException;

    /**
     * <code>addParams</code> adds a map of params one at a time
     * to the end of the command line.  It iterates over the hash
     * and does addParam(key, value).  The order is up to Map.
     * 
     * Example: command key1=value1 key2=value2 key3=value3
     *       
     * @param pArgs a <code>Map</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addParams(Map pArgs) throws IllegalAccessException;

    /**
     * <code>addAnonParams</code> added for workflow.
     *
     * @param pArgs a <code>Map</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addAnonParams(Map pArgs) throws IllegalAccessException;
    
    /**
     * <code>addParam</code> adds a parameter to the end of the
     * command line when command is invoked.  The command line arguments
     * are appended in the order that they are added. Depending on the
     * paramter type how the arguments are added are different.
     * 
     * List of Types
     *
     * FILE: If the type is FILE then the value should be the file
     * that contains a list of values to use. The request will be run once
     * with each line in the file as the value.
     *
     * Example:
     *    setCommand("/foo/test.sh");
     *    add_param("-v");
     *    add_param("-d", "/foo/data", ParamType.FILE);
     *
     *    /foo/data contains:
     *    line 1. /usr/local/db/noest
     *    line 2. /usr/tmp/db
     * 
     * final commands:
     *  /foo/test.sh -v -d=/usr/local/db/noest
     *  /foo/test.sh -v -d=/usr/tmp/db
     *
     * TEMPFILE: The same as FILE except that the file containing the values
     *  is deleted once the request is finished.
     *
     * DIR: If the type is DIR then the value is a directory. The request
     * will be run once with each file in the directory as the value. 
     *
     *
     * @param pKey a <code>String</code> value
     * @param pValue a <code>String</code> value
     * @param pType a <code>ParamType</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addParam(String pKey, String pValue, ParamType pType) throws IllegalAccessException;

    /**
     *  <code>addParam</code> The same as addParam(key, value, type) except
     * there isn't a key added to each value.
     *
     * @param pValue a <code>String</code> value
     * @param pType a <code>ParamType</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void addParam(String pValue, ParamType pType) throws IllegalAccessException;

    /* meta info about the job */
    /**
     * <code>getPriority</code> get the priority of the request
     *
     * @return an <code>int</code> value
     */
    public int getPriority();

    /**
     * <code>setPriority</code> set the priority of the request.
     * The higher the number the higher the priority. 0 is the lowest
     * and 5 is the highest.  Any number above 5 will be considered the
     * same as 5 and number under 0 is considered 0.
     *
     * @param pPriority an <code>int</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setPriority(int pPriority) throws IllegalAccessException;


    /**
     * <code>getOpSys</code> get target operating system
     *
     * @return a <code>String</code> value
     */
    public String getOpSys();

    /**
     * <code>setOpSys</code> set the target operating system for the
     * command. Currently supported are "Linux", "Solaris", "OSF1".
     *  The String can contain a comma seperated list of operating systems
     *
     * @param pOpsys a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setOpSys(String pOpsys) throws IllegalAccessException;

    /**
     * <code>getHosts</code> get the target hostname list
     *
     * @return a <code>String</code> value
     */
    public String getHosts();

    /**
     * <code>getLogLocation</code>
     *
     * @return a <code>String</code> value
     */
    public String getLogLocation();

    /**
     * <code>setHosts</code> set the target host name for the 
     * command. 
     *  The String can contain a comma separated list of hostnames.
     *
     * @param pHosts a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setHosts(String pHosts) throws IllegalAccessException;

    /**
     * <code>getPassThrough</code> 
     *
     * @return a <code>String</code> value
     */
    public String getPassThrough();

    /**
     * <code>setPassThrough</code>
     *
     * @param pPassThrough a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setPassThrough(String pPassThrough) throws IllegalAccessException;
    

    /**
     * <code>setLength</code> of a individual command.
     *  Acceptable values of "short", "medium", "long", "forever"
     *
     * short job is less than 4 hours
     * medium job is less than 12 hours
     * long is less than 24 hours
     * forever don't ever stop
     *
     * @param p_length a <code>String</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setLength(String p_length) throws IllegalAccessException;
    
    /**
     * <code>getLength</code> get value of length
     *
     * @return a <code>String</code> value
     */
    public String getLength();


    /**
     * <code>getMemory</code> get the minimum amount of memory
     * a job requires in MB.
     *
     * @return an <code>int</code> value
     */
    public int getMemory();

    /**
     * <code>setMemory</code> set the minimum amount of memory 
     * a job requires in MB.
     *
     * @param pMemory an <code>int</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setMemory(int pMemory) throws IllegalAccessException;


    public void setCmdClass(String pClass) throws IllegalAccessException;

    public String getCmdClass();


    /**
     * <code>setGetEnv</code> set the flag that determines if the
     * environment is sent with the request.  The environment is either
     * the environment of the JVM or set by user by passing a Vector to 
     * the method setEnvList.
     *
     * @param pEnv a <code>boolean</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setGetEnv(boolean pEnv) throws IllegalAccessException;
    
    /**
     * <code>isGetEnv</code> will the environment be sent with the
     * request.
     *
     * @return a <code>boolean</code> value
     */
    public boolean isGetEnv();

    
    /**
     * <code>setEnvList</code> set the environment variables for the request.
     * The List should contain strings of the format key=value.
     *
     * @param pEnv a <code>Map</code> value
     */
    public void setEnv(Map<String, String> pEnv);
    
    /**
     * <code>getEnvList</code> get the environment vector for the request.
     *
     * @return a <code>List</code> value
     */
    public Map<String, String> getEnv();

    /**
     * <code>getRetryCount</code> get the number of times to retry a command
     * before giving up and setting the state to Failure
     *
     * @return an <code>int</code> value
     */
    public int getRetryCount();

    /**
     * <code>setRetryCount</code> set the number of times to retry a command
     * before giving up and setting the state to Failure.
     *
     * @param pTimes an <code>int</code> value
     * @exception IllegalAccessException if an error occurs
     */
    public void setRetryCount(int pTimes) throws IllegalAccessException;
    
    /**
     * <code>getTimes</code> get the number of time to run a command if
     * the number of times was set.
     *
     * @return an <code>int</code> value
     */
    public int getTimes();

    /**
     * <code>setTimes</code> set the number of times to run a command
     *
     * @param p_times an <code>int</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setTimes(int p_times) 
	throws IllegalAccessException;


    /**
     * <code>getMaxWorkers</code> is the fan out
     *
     * @return an <code>int</code> value
     */
    public int getMaxWorkers();

    /**
     * <code>setMaxWorkers</code> get the fan out
     *
     * @param pMax an <code>int</code> value
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void setMaxWorkers(int pMax) throws IllegalAccessException;

    /**
     * <code>submit</code> submit the request to the grid.  If the request is valid and
     * is accepted by the cluster a unique positive id will be returned.  If there is 
     * error or the request is rejected the id returned will be less then 1.
     *
     * @return a <code>long</code> a unique id assigned to the request
     * @exception IllegalAccessException if a request has already been submitted
     * @exception IOException if a network problem occurs
     */
    public long submit() throws IllegalAccessException, IOException;

    /**
     * The method <code>getMonitorHost</code> returns the host monitoring this request
     * 
     * @return a <code>String</code> representing the host name
     * 
     * @throws IOException if a network problem occurs
     */
    public String getMonitorHost () throws IllegalAccessException, IOException;

    /**
     * The method <code>getTasks</code> returns the tasks associated with the array request
     * 
     * @return a <code>TaskGroup</code> representing the task group
     * 
     * @exception IllegalAccessException if a request has already been submitted
     * @throws IOException if a network problem occurs
     */
    public TaskGroup getTasks () throws IllegalAccessException, IOException;
    
    /**
     * <code>stop</code> send a stop to the request.  This method doesn't
     * wait for the command to stop before it returns.
     *
     * @exception IllegalAccessException if the request hasn't been submitted
     */
    public void stop() throws IllegalAccessException, IOException;
    
    /**
     * <code>resume</code> send a resume command to a request that has been
     * held/suspended by the user.  This will cause the request to 
     * be put back in a queue to be scheduled. This method doesn't
     * wait for the command to stop before it returns. 
     *
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void resume() 
	throws IllegalAccessException, IOException;

    /**
     *  <code>hold</code> send a hold/suspend command to a request. 
     *
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void hold() throws IllegalAccessException, IOException;

    /**
     * <code>waitForRequest</code> wait for the request to finish.
     *
     * @return a <code>long</code> id for the request that finished
     * @exception IllegalAccessException if request hasn't been submitted
     * @exception InterruptedException if interrupted while waiting
     */
    public long waitForRequest() throws IllegalAccessException, InterruptedException;

    /**
     * <code>disconnect</code> client no longer wants event updates from server
     *
     * @exception IllegalAccessException if set is attempted after submission
     */
    public void disconnect() throws IllegalAccessException, IOException;


    //
    // event listener stuff
    //

    /**
     * <code>addLifetimeListener</code> add pListen to queue
     * of listeners that what to receive lifetime events
     *
     * @param pListen a <code>CommandLifetimeLI</code> value
     */
    public void addLifetimeListener(CommandLifetimeLI pListen);

    /**
     * <code>removeLifetimeListener</code> remove pListen from the queue
     * of listeners that what to receive lifetime events
     *
     * @param pListen a <code>CommandLifetimeLI</code> value
     */
    public void removeLifetimeListener(CommandLifetimeLI pListen);


    /**
     * <code>addRuntimeStatusListener</code> add pListen to queue
     * of listeners that what to receive RuntimeStatus events
     *
     * @param pListen a <code>CommandRuntimeStatusLI</code> value
     */
    public void addRuntimeStatusListener(CommandRuntimeStatusLI pListen);

    /**
     * <code>removeRuntimeStatusListener</code> remove pListen from the queue
     * of listeners that what to receive RuntimeStatus events
     *
     * @param pListen a <code>CommandRuntimeStatusLI</code> value
     */
    public void removeRuntimeStatusListener(CommandRuntimeStatusLI pListen);


    /**
     * <code>addStatusListener</code> add pListen to queue
     * of listeners that what to receive Status events
     *
     * @param pListen a <code>CommandStatusLI</code> value
     */
    public void addStatusListener(CommandStatusLI pListen);

    /**
     * <code>removeStatusListener</code> remove pListen from the queue
     * of listeners that what to receive Status events
     *
     * @param pListen a <code>CommandStatusLI</code> value
     */
    public void removeStatusListener(CommandStatusLI pListen);
    
    /**
     * 
     * @return
     */
    public String toXML();
    
    public void setRunningTime(long minutes) throws IllegalAccessException;
    
    public long getRunningTime();
    
    public void setEvictable(boolean evictable) throws IllegalAccessException;
    
    public boolean isEvictable();
    
    public String getGridJobId() throws IOException;
    
    public void setGridJobId(String gridId); 
    
    /**
     * <code>setSubmitTime</code> set the submit time.
     *
     * @param pSubmitTime a <code>Date</code> of submit time value
     */
    public void setSubmitTime(Date pSubmitTime);
     
    /**
     * <code>getSubmitTime</code> get the submit time.
     *
     * @return a <code>Date</code> of submit time
     */
    public Date getSubmitTime();

    /**
     * <code>setStartTime</code> the start time.
     *
     * @param pStartTime a <code>Date</code> of start time value
     */
    public void setStartTime(Date pStartTime);

    /**
     * <code>getStartTime</code> get the start time.
     *
     * @return a <code>Date</code> of start time
     */
    public Date getStartTime();

    /**
     * <code>setEndTime</code> set the end time
     *
     * @param pEndTime a <code>Date</code> of end time
     */
    public void setEndTime(Date pEndTime);

    /**
     * <code>getEndTime</code> get the end time
     *
     * @return a <code>Date</code> value
     */
    public Date getEndTime();
    
}
